package standalone_storage

import (
	"github.com/Connor1996/badger"
	"github.com/pingcap-incubator/tinykv/kv/config"
	"github.com/pingcap-incubator/tinykv/kv/storage"
	"github.com/pingcap-incubator/tinykv/kv/util/engine_util"
	"github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb"
)

// StandAloneStorage is an implementation of `Storage` for a single-node TinyKV instance. It does not
// communicate with other nodes and all data is stored locally.
type StandAloneStorage struct {
	// Your Data Here (1).
	engine *engine_util.Engines
}
type Reader struct {
	s        *StandAloneStorage
	txn      *badger.Txn
	iterator engine_util.DBIterator
}

func (r *Reader) GetCF(cf string, key []byte) ([]byte, error) {
	val, _ := engine_util.GetCF(r.s.engine.Kv, cf, key)
	return val, nil
}

func (r *Reader) IterCF(cf string) engine_util.DBIterator {
	if r.iterator == nil {
		r.txn = r.s.engine.Kv.NewTransaction(false)
		r.iterator = engine_util.NewCFIterator(cf, r.txn)
	}
	return r.iterator
}
func (r *Reader) Close() {
	if r.txn != nil {
		r.txn.Discard()
	}
	if r.iterator != nil {
		r.iterator.Close()
	}
}
func NewStandAloneStorage(conf *config.Config) *StandAloneStorage {
	// Your Code Here (1).
	kvDB := engine_util.CreateDB(conf.DBPath+"/kv", false)
	raftDB := engine_util.CreateDB(conf.DBPath+"/raft", true)
	return &StandAloneStorage{engine: engine_util.NewEngines(kvDB, raftDB, conf.DBPath+"/kv", conf.DBPath+"/raft")}
}

func (s *StandAloneStorage) Start() error {
	// Your Code Here (1).
	return nil
}

func (s *StandAloneStorage) Stop() error {
	// Your Code Here (1).
	return s.engine.Destroy()
}

func (s *StandAloneStorage) Reader(ctx *kvrpcpb.Context) (storage.StorageReader, error) {
	// Your Code Here (1).
	return &Reader{s: s}, nil
}

func (s *StandAloneStorage) Write(ctx *kvrpcpb.Context, batch []storage.Modify) error {
	// Your Code Here (1).
	writeBatch := engine_util.WriteBatch{}
	for _, b := range batch {
		writeBatch.SetCF(b.Cf(), b.Key(), b.Value())
	}
	return writeBatch.WriteToDB(s.engine.Kv)
}
